#ifndef BEHAVIORGRIDCLIENT_H
#define BEHAVIORGRIDCLIENT_H

#include <boost/asio.hpp>
#include <boost/cstdint.hpp>
#include <BehaviorHandler.h>
#include <GridPackedMessage.h>
#include "gridprotocol.pb.h"
#include "TEMP__PluginContainer.h"
#include <vector>
#include <Utils.h>

using namespace std;
using boost::uint8_t;
namespace gPt = gridprotocol;
using namespace Network;
using namespace MasterWorkerFramework;

class BehaviorGridClient : public BehaviorHandler<gridprotocol::Request,gridprotocol::Response>
{
public:
	
		BehaviorGridClient()
			:BehaviorHandler(){
			task_container_ = new PluginContainer();
			SetKillSwitch (false);
			name_ =GetRandomString();
		}

		~BehaviorGridClient(){};


		void SetKillSwitch(bool isKill)
		{
			killSwitch_ = isKill;
		}

		bool GetKillSwitch ()
		{
			return killSwitch_;
		}

		gridprotocol::Request* NewRequestMessage()
		{
			gridprotocol::Request* msg = new gridprotocol::Request();
			return msg;
		}

		boost::shared_ptr<gridprotocol::Request> NewRequestSharedPtr()
		{
			return boost::shared_ptr<gridprotocol::Request>(NewRequestMessage());
		}

		boost::shared_ptr<gridprotocol::Response> NewResponseSharedPtr()
		{
			return boost::shared_ptr<gridprotocol::Response>(NewResponseMessage());
		}

		gridprotocol::Response* NewResponseMessage()
		{
			gridprotocol::Response* msg = new gridprotocol::Response();
			return msg;
		}

		void HandleResponse(gridprotocol::Response &response,gridprotocol::Request &request,  void* args)
		{
			return;
		}
		void HandleRequest (gridprotocol::Response &response, gridprotocol::Request &request, void* args)
		{

		std::vector<uint8_t> writebuf;
		SetKillSwitch (false);

		switch (request.type())
			
		{
			case gPt::Request::ASK_AVAIL:
				{
					response.set_type (gPt::Response::ACK_AVAIL);
					gPt::Response_ResponseAckAvail* avail =  response.mutable_response_ack_avail();//.set_available(true);
					avail->set_available(true);
					break;
				}
			case gPt::Request::ASK_ID:
				{
					response.set_type(gPt::Response::ACK_ID);
					gPt::Response_ResponseAckId* id = response.mutable_response_ack_id();
					std::stringstream str;
					srand(time(NULL));
					Sleep(1000);
					str <<rand();
					id->set_m_id(name_);
					break;
				}
			case gPt::Request::ASK_TASK:
				{
					std::string* task_name = request.mutable_request_ask_task()->mutable_t_name();
					AbstractGridSlaveTask* task = task_container_->GetTask(task_name);
					task->GetBindedResult()->clear();
					//mem leak
					response.set_type(gPt::Response::ACK_RESULT);
					gPt::Response_ResponseAckResult* result = response.mutable_response_ack_result();
					result->set_t_id(request.request_ask_task().t_id());
					result->set_t_name(request.request_ask_task().t_name());

					result->set_result_count(1);
					gPt::Param* param1 = result->add_results();

					TaskResult* r;

					for (int i=0; i<request.request_ask_task().param().size();i++)
					{
						switch (request.request_ask_task().param().Get(i).type())
						{
							case gPt::Param::TYPE_FLOAT:
								{
									float* f = new float(request.request_ask_task().param().Get(i).request_param_float().value());
									r= new TaskResult(VALUE_TYPE::VALUE_TYPE_FLOAT);
									r->SetResult<float>(f);
									task->AppendResult(r);
									break;
								}
							case gPt::Param::TYPE_INT32:
								{
									int* f = new int(request.request_ask_task().param().Get(i).request_param_int32().value());
									r= new TaskResult(VALUE_TYPE::VALUE_TYPE_INT32);
									r->SetResult<int>(f);
									task->AppendResult(r);
									break;
								}
							case gPt::Param::TYPE_STRING:
								{
									std::string* f = new std::string(request.request_ask_task().param().Get(i).request_param_string().value());
									r= new TaskResult(VALUE_TYPE::VALUE_TYPE_STRING);
									r->SetResult<std::string>(f);
									task->AppendResult(r);
									break;
								}
						}
					}

					switch (task->GetTaskType())
					{
						case VALUE_TYPE::VALUE_TYPE_FLOAT:
							{
								param1->set_type(gPt::Param::TYPE_FLOAT);
								gPt::Param_ParamFloat* p_float = param1->mutable_request_param_float();
								task->Execute();
								float* f_ptr = task->GetResult()->GetResult<float>();
								p_float->set_value (*f_ptr);
								break;
							}
						case VALUE_TYPE::VALUE_TYPE_INT32:
							{
								param1->set_type(gPt::Param::TYPE_INT32);
								gPt::Param_ParamInt32* p_int = param1->mutable_request_param_int32();
								task->Execute();
								int* i_ptr = task->GetResult()->GetResult<int>();
								p_int->set_value (*i_ptr);
								break;
							}
						case VALUE_TYPE::VALUE_TYPE_STRING:
							{
								param1->set_type(gPt::Param::TYPE_STRING);
								gPt::Param_ParamString* p_string = param1->mutable_request_param_string();
								task->Execute();
								std::string* s_ptr = task->GetResult()->GetResult<std::string>();
								p_string->set_value (*s_ptr);
								break;
							}
					}

					/*switch (task->GetTaskType())
					{
						case VALUE_TYPE::VALUE_TYPE_FLOAT:
							{
							param1->set_type(gPt::Param::TYPE_FLOAT);
							gPt::Param_ParamFloat* p_float = param1->mutable_request_param_float();

							if (request.request_ask_task().param().size()>0)
							{
								for (int i=0; i<request.request_ask_task().param().size();i++)
								{
									float* f = new float(request.request_ask_task().param().Get(i).request_param_float().value());
									r= new TaskResult(VALUE_TYPE::VALUE_TYPE_FLOAT);
									r->SetResult<float>(f);
									task->AppendResult(r);
								}
							}

							task->Execute();
							float* f_ptr = task->GetResult()->GetResult<float>();
							p_float->set_value (*f_ptr);
							break;
							}
						case VALUE_TYPE::VALUE_TYPE_INT32:
							{
							param1->set_type(gPt::Param::TYPE_INT32);
							gPt::Param_ParamInt32* p_int = param1->mutable_request_param_int32();

							if (request.request_ask_task().param().size()>0)
							{
								for (int i=0; i<request.request_ask_task().param().size();i++)
								{
									int* f = new int(request.request_ask_task().param().Get(i).request_param_int32().value());
									r= new TaskResult(VALUE_TYPE::VALUE_TYPE_INT32);
									r->SetResult<int>(f);
									task->AppendResult(r);
								}
							}

							task->Execute();
							int* i_ptr = task->GetResult()->GetResult<int>();
							p_int->set_value (*i_ptr);
							break;
							}
						case VALUE_TYPE::VALUE_TYPE_STRING:
							{
							param1->set_type(gPt::Param::TYPE_STRING);
							gPt::Param_ParamString* p_string = param1->mutable_request_param_string();

							if (request.request_ask_task().param().size()>0)
							{
								for (int i=0; i<request.request_ask_task().param().size();i++)
								{
									std::string* f = new std::string(request.request_ask_task().param().Get(i).request_param_string().value());
									r= new TaskResult(VALUE_TYPE::VALUE_TYPE_STRING);
									r->SetResult<std::string>(f);
									task->AppendResult(r);
								}
							}

							task->Execute();
							std::string* s_ptr = task->GetResult()->GetResult<std::string>();
							p_string->set_value (*s_ptr);
							break;
							}
					}*/

					break;
				}
			case gPt::Request::ASK_DIE:
					SetKillSwitch (true);
					break;
			default:
				break;
			}
		}

		char* GetName()
		{
			return name_;
		}

	private:
		bool killSwitch_;
		char* name_;
		PluginContainer* task_container_;
};

#endif